﻿using System;
using System.Windows;
using Microsoft.Practices.Composite.Modularity;

namespace PrismNavigationFramework.Infrastructure
{
    public enum ModuleDownloadStatus
    {
        StartingDownload = 0,
        DownloadCompleted = 1
    }

    public class ModuleDownloadStateChangedEventArgs : EventArgs
    {
        public ModuleDownloadStatus ModuleDownloadStatus { get; set; }
        public string ModuleUrlFriendlyName { get; set; }
        public string ModuleName { get; set; }
        public bool ThereWereErrors
        {
            get { return Error != null; }
        }
        public Exception Error { get; set; }
    }

    public class PrismModuleLoadingService : IPrismModuleLoadingService
    {
        private readonly IModuleManager _moduleManager;
        private readonly ILoadedModulesRegistrationService _loadedModulesRegistrationService;
        private readonly IModuleNamesRegistrationService _moduleNameTranslationService;

        public PrismModuleLoadingService(IModuleManager moduleManager, ILoadedModulesRegistrationService loadedModulesRegistrationService, IModuleNamesRegistrationService moduleNameTranslationService)
        {
            _loadedModulesRegistrationService = loadedModulesRegistrationService;
            _moduleNameTranslationService = moduleNameTranslationService;
            _moduleManager = moduleManager;

            _moduleManager.LoadModuleCompleted += ModuleManagerLoadModuleCompleted;
        }

        void ModuleManagerLoadModuleCompleted(object sender, LoadModuleCompletedEventArgs e)
        {
            Deployment.Current.Dispatcher.BeginInvoke(() =>
                                                          {
                                                              this.OnModuleDownloadStateChanged(
                                                                  e.ModuleInfo.ModuleName,
                                                                  ModuleDownloadStatus.DownloadCompleted, e.Error);
                                                          });
        }

        public EventHandler<ModuleDownloadStateChangedEventArgs> ModuleDownloadStateChanged
        {
            get;
            set;
        }

        protected void OnModuleDownloadStateChanged(string moduleName, ModuleDownloadStatus status)
        {
            this.OnModuleDownloadStateChanged(moduleName, status, null);
        }

        protected void OnModuleDownloadStateChanged(string moduleName, ModuleDownloadStatus status, Exception error)
        {
            var handler = this.ModuleDownloadStateChanged;
            if (handler != null)
            {
                handler(this, new ModuleDownloadStateChangedEventArgs()
                                  {
                                      ModuleName = moduleName,
                                      ModuleDownloadStatus = status,
                                      Error = error
                });
            }
        }

        public bool ModuleNeedsToBeLoaded(string moduleName)
        {
            return !this._loadedModulesRegistrationService.ModuleIsLoaded(moduleName);
        }

        public void LoadModule(string moduleUrlFriendlyName)
        {
            try
            {
                this.OnModuleDownloadStateChanged(moduleUrlFriendlyName, ModuleDownloadStatus.StartingDownload);

                var realModuleName =
                    this._moduleNameTranslationService.GetRealModuleName(moduleUrlFriendlyName);

                try
                {
                    Deployment.Current.Dispatcher.BeginInvoke(() => this._moduleManager.LoadModule(realModuleName));
                }
                catch (Exception e)
                {
                    Deployment.Current.Dispatcher.BeginInvoke(() => this.OnModuleDownloadStateChanged(moduleUrlFriendlyName, ModuleDownloadStatus.DownloadCompleted, e));
                }              
            }
            catch (Exception ex)
            {
                this.OnModuleDownloadStateChanged(moduleUrlFriendlyName, ModuleDownloadStatus.DownloadCompleted, ex);
                throw;
            }
        }
    }
}